from datetime import datetime

from rest_framework import status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.serializers import JSONWebTokenSerializer

from backend.utils.base_serializer import SerializerFactory
from backend.utils.base_viewsets import BaseModelViewSet
from backend.utils.filters import CustomFilterBackend
from backend.utils.jwt import jwt_response_payload_handler
from backend.utils.jwt_authenticate import MyJSONWebTokenAuthentication
from backend.utils.pagination import CustomPagination
from backend.utils.redis_utils import RedisUtils
from backend.utils.response import ApiResponse
from permissions.models import Role
from users.models import User, File
from users.serializers import UserDefaultSerializer, UserInfoSerializer, UserUpdateSerializer, FileModelSerializer


class UserModelViewSet(BaseModelViewSet):
    serializer_class = {
        'default': UserDefaultSerializer,
        'update': UserUpdateSerializer,
        'login': JSONWebTokenSerializer,
        'get_userinfo': UserInfoSerializer,
        'assign_role': SerializerFactory.build(User, fields=['roles']),
        'update_roles': SerializerFactory.build(User, fields=['roles']),
    }
    white_list = ['login', ]
    queryset = User.advanced_objects.all()
    pagination_class = CustomPagination
    filter_backends = [CustomFilterBackend]
    search_fields = ['username', 'mobile']

    def get_queryset(self):
        return self.queryset.all()

    @action(methods=['GET'], detail=False, url_path='info', permission_classes=[IsAuthenticated])
    def get_userinfo(self, request):
        serializer = self.get_serializer(request.user)
        return ApiResponse(data=serializer.data)

    @action(methods=['POST'], detail=False, url_path='login', url_name='login', permission_classes=[])
    def login(self, request):
        serializer = self.get_serializer(data=request.data)

        if serializer.is_valid():
            user = serializer.object.get('user') or request.user
            if not user.is_superuser and user.roles.count() < 1:
                return ApiResponse(message='该用户未分配角色,无法登录', code=400)
            user.last_login = datetime.now()
            user.save()
            user.set_permission_code()
            token = serializer.object.get('token')
            response_data = jwt_response_payload_handler(token, user, request)
            response = ApiResponse(data=response_data, code=200)
            if api_settings.JWT_AUTH_COOKIE:
                expiration = (datetime.utcnow() +
                              api_settings.JWT_EXPIRATION_DELTA)
                response.set_cookie(api_settings.JWT_AUTH_COOKIE,
                                    token,
                                    expires=expiration,
                                    httponly=True)
            return response

        return ApiResponse(message=serializer.errors, code=400, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['POST'], detail=False, url_name='logout', url_path='logout', permission_classes=[IsAuthenticated])
    def logout(self, request, *args, **kwargs):
        token = request.headers.get('Authorization')
        RedisUtils('token').delete(token)
        RedisUtils('permission').delete(f'permission_code_{request.user.pk}')
        return ApiResponse(code=200, message='ok')

    @action(methods=['GET'], detail=True, url_path='assign_role', url_name='assign_role',
            permission_classes=[IsAuthenticated])
    def assign_role(self, request, *args, **kwargs):
        user = self.get_object()
        serializer = self.get_serializer(user)
        # 该用户已有的角色
        user_roles = serializer.data
        # 所有角色
        role_list = Role.advanced_objects.all()
        role_serializer_class = SerializerFactory.build(Role, fields=['id', 'name', 'remark'])
        role_serializer = role_serializer_class(role_list, many=True)
        return ApiResponse(data={**user_roles, 'role_list': role_serializer.data})

    @assign_role.mapping.put
    def update_roles(self, request, *args, **kwargs):
        user = self.get_object()
        data = request.data
        serializer = self.get_serializer(user, data=data)
        serializer.is_valid(raise_exception=True)
        roles = data.get('roles', [])
        if not roles:
            return ApiResponse(code=400, message='未选择需要分配的角色')
        role_list = Role.advanced_objects.filter(id__in=roles)
        if len(role_list) != len(roles):
            return ApiResponse(code=400, message='传了不存在的角色id')
        user.roles.set(role_list)
        return ApiResponse(message='角色分配成功')


class FileModelViewSet(ModelViewSet):
    authentication_classes = [MyJSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated]
    queryset = File.objects.all()
    serializer_class = FileModelSerializer
